package com.cet.qz.unit01.chapter1_3;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @program: algorithm
 * @description: 环形缓冲区
 * @author: 陈恩涛
 * @create: 2021-04-23 16:19
 **/
public class RightBuffer<Item> {

    private Item[] a;
    private int first,last, n;

    private final Lock lock;
    private final Condition notFull;
    private final Condition notEmpty;

    public RightBuffer(int capacity) {
        a = (Item[]) new Object[capacity];
        first = 0;
        last = 0;
        n = 0;
        lock = new ReentrantLock();
        notFull = lock.newCondition();
        notEmpty = lock.newCondition();
    }

    public boolean isEmpty() {
        return first == last;
    }

    public boolean isFull() {
        return first == (last + 1) % a.length;
    }

    public int size() {
        return n;
    }

    public void enqueue(Item item) throws InterruptedException {

        lock.lock();
        try {
            while (isFull()) {
                System.out.println("队列已满，入队阻塞！");
                notFull.await();
            }
            a[last] = item;
            last = (last + 1) % a.length;
            n++;
            System.out.println(Thread.currentThread().getName()+"====》"+n);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public Item dequeue() throws InterruptedException {
        lock.lock();

        try {
            while (isEmpty()) {
                System.out.println("队列为空，出队阻塞！");
                notEmpty.await();
            }
            Item result = a[first];
            a[first] = null;
            first = (first + 1) % a.length;
            n--;
            System.out.println(Thread.currentThread().getName()+"====》"+n);
            notFull.signal();
            return result;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        RightBuffer<Integer> rightBuffer = new RightBuffer<>(5);

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        try {
            threadPool.execute(() ->{
                for (int i = 0; i < 100; i++) {
                    try {
                        rightBuffer.enqueue(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            threadPool.execute(() ->{
                for (int i = 0; i < 100; i++) {
                    try {
                        rightBuffer.dequeue();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        } finally {
            threadPool.shutdown();
        }
    }



}
